//
// Created by kqzhang on 2022/3/18.
//

#ifndef HUAWEI_C___MODEL_H
#define HUAWEI_C___MODEL_H

#include "header.h"
#include "File.h"
#include "Site.h"
#include "Individual.h"

class Model {
public:
    Model() = default;
    Model(string &root);
    void initData();
    void GA();
    void test();
    void assignOne();
    void assignTwo();
    void assignThree();
    void testTwo();

private:
    // site and user data
    File file;
    int m = 0, n = 0;       // m -- user n -- site
    int qosConstraint = 0;
    vector<string> user;
    vector<Site> allSite;
    vector<vector<int>> demand;
    vector<vector<double>> normalizeQos;
    // ans
    vector<Individual> bestIndividual;
    vector<vector<int>> oldDistribute;

    // init site and user data
    void initQosConstraint();
    void initDatOfSite();
    void initUser();
    void initDemand();
    void initNormalizeQos(vector<vector<int>> &qos);

    /*
     * GA
    */
    const int groupSize = 5;
    const int generationTime = 50;
    const double pc = 0.7;
    const double pm = 0.1;
    vector<int> currentDemand;
    vector<Individual> individual;

    void initGroup();
    void crossover();
    void mutation();
    void select();
    void getFitness(Individual &individual);
    int getFitness();

    //init meanFunction
    void getMeanIndividual(Individual &individual);
    void updateOldDistribute(vector<vector<int>> &distribute);

    // init function
    void getRandomValue(int num, int allBand, vector<int> &disOfUser);
    bool check(Individual &individual);

    // crossover two individual
    void crossTwoIndividual(Individual &one, Individual &two);

    // write result
    void printResult();

    //test function
    int sum(Individual &test);
    int sum(vector<int> &test);
    double sum(vector<double> &test);
    bool checkBand(vector<vector<int>> &distribute);

    /**
     * assign one
     */
    vector<int> midValue;
    vector<Individual> final;
    const double meanPercentage = 0.95;

    void createIndividual(vector<vector<int>> &distribute);
    void getAssignValue(vector<vector<int>> &distribute, vector<vector<int>> &connectSite);
    void meanValue(vector<int> &meanNValue, int all, int n);
    void updateMidValue(int T);

    /**
     * assign two
     */
    vector<vector<double>> connectSiteNor;

    /**
     * three
     */
    int expectTimeDemand = 0;

    vector<preAssign> top5Assign;
    vector<vector<vector<bool>>> isConnect;
    priority_queue<PII, vector<PII>> bandSitePq;
    vector<vector<int>> siteConnectUser;
    vector<vector<int>> preLeftBand;
    vector<int> userConnectSite;

    void getTop5Assign();
    void assign();
    void singleAssign(vector<vector<int>> &distribute, int T); // before assign
    void avgAssign(vector<vector<int>> &distribute, int T); // avg assign
    void proportionAssign(vector<vector<int>> &distribute, int T);

};

inline bool cmp(Individual &a, Individual &b) {
    return a.getFitness() < b.getFitness();
}

inline double random_0_1() {
    return (rand() % 10000) / (double)(10000 + 1);
}

#endif //HUAWEI_C___MODEL_H
